"""
数据可视化仪表盘模块
"""
import dash
from dash import dcc, html, callback, Input, Output, State
import dash_bootstrap_components as dbc
import plotly.express as px
import plotly.graph_objects as go
import pandas as pd
from datetime import datetime, timedelta
from sqlalchemy import func, desc, and_
from sqlalchemy.orm import scoped_session, sessionmaker

from modules.models.base import engine
from modules.models import (
    SecurityInfo, DailyQuote, TechnicalIndicator, CollectionTask,
    MacroEconomicData, EconomicNews
)


# 创建数据库会话
Session = scoped_session(sessionmaker(bind=engine))


# 创建仪表盘应用
def create_task_dashboard(server):
    """
    创建任务监控仪表盘
    
    Args:
        server: Flask服务器实例
    
    Returns:
        Dash应用实例
    """
    dash_app = dash.Dash(
        name='tasks_dashboard',
        server=server,
        url_base_pathname='/dash/tasks/',
        external_stylesheets=[dbc.themes.BOOTSTRAP]
    )
    
    # 定义布局
    dash_app.layout = html.Div([
        dbc.Container([
            html.H1("任务监控仪表盘", className="text-center my-4"),
            
            dbc.Row([
                dbc.Col([
                    dbc.Card([
                        dbc.CardHeader("任务状态统计"),
                        dbc.CardBody([
                            dcc.Graph(id='task-status-pie')
                        ])
                    ])
                ], width=6),
                
                dbc.Col([
                    dbc.Card([
                        dbc.CardHeader("每日任务趋势"),
                        dbc.CardBody([
                            dcc.Graph(id='task-trend-line')
                        ])
                    ])
                ], width=6)
            ], className="mb-4"),
            
            dbc.Row([
                dbc.Col([
                    dbc.Card([
                        dbc.CardHeader("任务类型分布"),
                        dbc.CardBody([
                            dcc.Graph(id='task-type-bar')
                        ])
                    ])
                ], width=12)
            ], className="mb-4"),
            
            dbc.Row([
                dbc.Col([
                    dbc.Card([
                        dbc.CardHeader("最近任务执行情况"),
                        dbc.CardBody([
                            html.Div(id='recent-tasks-table')
                        ])
                    ])
                ], width=12)
            ]),
            
            dcc.Interval(
                id='interval-component',
                interval=60*1000,  # 每分钟更新一次
                n_intervals=0
            )
        ], fluid=True)
    ])
    
    # 回调函数：更新任务状态饼图
    @dash_app.callback(
        Output('task-status-pie', 'figure'),
        [Input('interval-component', 'n_intervals')]
    )
    def update_task_status_pie(n):
        session = Session()
        try:
            # 查询任务状态统计
            results = session.query(
                CollectionTask.status,
                func.count(CollectionTask.id).label('count')
            ).group_by(CollectionTask.status).all()
            
            # 转换为DataFrame
            df = pd.DataFrame([(r[0], r[1]) for r in results], columns=['status', 'count'])
            
            # 创建饼图
            fig = px.pie(
                df, 
                names='status', 
                values='count',
                title='任务执行状态分布',
                color='status',
                color_discrete_map={
                    'success': '#28a745',
                    'failed': '#dc3545',
                    'pending': '#ffc107',
                    'running': '#17a2b8',
                    'revoked': '#6c757d'
                }
            )
            fig.update_traces(textposition='inside', textinfo='percent+label')
            return fig
        finally:
            session.close()
    
    # 回调函数：更新任务趋势图
    @dash_app.callback(
        Output('task-trend-line', 'figure'),
        [Input('interval-component', 'n_intervals')]
    )
    def update_task_trend_line(n):
        session = Session()
        try:
            # 计算过去30天的日期
            end_date = datetime.now()
            start_date = end_date - timedelta(days=30)
            
            # 查询每天的任务数量
            results = session.query(
                func.date(CollectionTask.create_time).label('date'),
                func.count(CollectionTask.id).label('count')
            ).filter(
                CollectionTask.create_time >= start_date
            ).group_by(
                func.date(CollectionTask.create_time)
            ).order_by(
                func.date(CollectionTask.create_time)
            ).all()
            
            # 转换为DataFrame
            df = pd.DataFrame([(r[0], r[1]) for r in results], columns=['date', 'count'])
            
            # 确保日期连续
            date_range = pd.date_range(start=start_date.date(), end=end_date.date())
            full_df = pd.DataFrame({'date': date_range})
            df = pd.merge(full_df, df, on='date', how='left').fillna(0)
            
            # 创建折线图
            fig = px.line(
                df, 
                x='date', 
                y='count',
                title='每日任务执行趋势',
                labels={'date': '日期', 'count': '任务数量'}
            )
            fig.update_traces(mode='lines+markers')
            return fig
        finally:
            session.close()
    
    # 回调函数：更新任务类型柱状图
    @dash_app.callback(
        Output('task-type-bar', 'figure'),
        [Input('interval-component', 'n_intervals')]
    )
    def update_task_type_bar(n):
        session = Session()
        try:
            # 查询任务类型统计
            results = session.query(
                CollectionTask.task_type,
                func.count(CollectionTask.id).label('count')
            ).group_by(CollectionTask.task_type).all()
            
            # 转换为DataFrame
            df = pd.DataFrame([(r[0], r[1]) for r in results], columns=['task_type', 'count'])
            
            # 创建柱状图
            fig = px.bar(
                df, 
                x='task_type', 
                y='count',
                title='任务类型分布',
                labels={'task_type': '任务类型', 'count': '任务数量'}
            )
            return fig
        finally:
            session.close()
    
    # 回调函数：更新最近任务表格
    @dash_app.callback(
        Output('recent-tasks-table', 'children'),
        [Input('interval-component', 'n_intervals')]
    )
    def update_recent_tasks_table(n):
        session = Session()
        try:
            # 查询最近100个任务
            tasks = session.query(CollectionTask).order_by(
                desc(CollectionTask.create_time)
            ).limit(100).all()
            
            # 创建表格
            table_header = [
                html.Thead(html.Tr([
                    html.Th("任务ID"),
                    html.Th("任务类型"),
                    html.Th("证券代码"),
                    html.Th("状态"),
                    html.Th("结果数量"),
                    html.Th("创建时间"),
                    html.Th("更新时间")
                ]))
            ]
            
            table_rows = []
            for task in tasks:
                row_color = {
                    'success': 'table-success',
                    'failed': 'table-danger',
                    'pending': 'table-warning',
                    'running': 'table-info',
                    'revoked': 'table-secondary'
                }.get(task.status, '')
                
                row = html.Tr([
                    html.Td(task.task_id[:8] + '...' if task.task_id else '-'),
                    html.Td(task.task_type),
                    html.Td(task.security_code or '-'),
                    html.Td(task.status),
                    html.Td(task.result_count),
                    html.Td(task.create_time.strftime('%Y-%m-%d %H:%M:%S')),
                    html.Td(task.update_time.strftime('%Y-%m-%d %H:%M:%S'))
                ], className=row_color)
                
                table_rows.append(row)
            
            table_body = [html.Tbody(table_rows)]
            
            return dbc.Table(table_header + table_body, bordered=True, hover=True, responsive=True, striped=True)
        finally:
            session.close()
    
    return dash_app


def create_market_dashboard(server):
    """
    创建市场数据仪表盘
    
    Args:
        server: Flask服务器实例
    
    Returns:
        Dash应用实例
    """
    dash_app = dash.Dash(
        name='market_dashboard',
        server=server,
        url_base_pathname='/dash/market/',
        external_stylesheets=[dbc.themes.BOOTSTRAP]
    )
    
    # 获取所有股票列表
    session = Session()
    stocks = session.query(SecurityInfo).filter(
        SecurityInfo.type == 'stock',
        SecurityInfo.is_active == 1
    ).all()
    stock_options = [{'label': f"{s.code} - {s.name}", 'value': s.code} for s in stocks]
    session.close()
    
    # 定义布局
    dash_app.layout = html.Div([
        dbc.Container([
            html.H1("市场数据分析", className="text-center my-4"),
            
            dbc.Row([
                dbc.Col([
                    dbc.Card([
                        dbc.CardHeader("证券选择"),
                        dbc.CardBody([
                            dcc.Dropdown(
                                id='stock-dropdown',
                                options=stock_options,
                                value=stock_options[0]['value'] if stock_options else None,
                                placeholder="选择证券..."
                            ),
                            html.Div(id='stock-info', className="mt-3")
                        ])
                    ])
                ], width=12)
            ], className="mb-4"),
            
            dbc.Row([
                dbc.Col([
                    dbc.Card([
                        dbc.CardHeader("价格走势图"),
                        dbc.CardBody([
                            dcc.DatePickerRange(
                                id='date-range',
                                start_date_placeholder_text="开始日期",
                                end_date_placeholder_text="结束日期",
                                calendar_orientation='horizontal',
                            ),
                            dcc.Graph(id='price-chart')
                        ])
                    ])
                ], width=12)
            ], className="mb-4"),
            
            dbc.Row([
                dbc.Col([
                    dbc.Card([
                        dbc.CardHeader("技术指标"),
                        dbc.CardBody([
                            dbc.Row([
                                dbc.Col([
                                    dcc.Dropdown(
                                        id='indicator-dropdown',
                                        options=[
                                            {'label': 'MA - 移动平均线', 'value': 'ma'},
                                            {'label': 'MACD - 异同移动平均线', 'value': 'macd'},
                                            {'label': 'RSI - 相对强弱指标', 'value': 'rsi'},
                                            {'label': 'BOLL - 布林带', 'value': 'boll'}
                                        ],
                                        value='ma',
                                        placeholder="选择技术指标..."
                                    )
                                ], width=12)
                            ], className="mb-3"),
                            dcc.Graph(id='indicator-chart')
                        ])
                    ])
                ], width=12)
            ])
        ], fluid=True)
    ])
    
    # 回调函数：显示股票信息
    @dash_app.callback(
        Output('stock-info', 'children'),
        [Input('stock-dropdown', 'value')]
    )
    def update_stock_info(stock_code):
        if not stock_code:
            return html.Div("请选择证券", className="text-muted")
        
        session = Session()
        try:
            # 查询股票信息
            stock = session.query(SecurityInfo).filter(
                SecurityInfo.code == stock_code
            ).first()
            
            if not stock:
                return html.Div("未找到证券信息", className="text-danger")
            
            # 查询最新行情
            latest_quote = session.query(DailyQuote).filter(
                DailyQuote.security_id == stock.id
            ).order_by(desc(DailyQuote.trade_date)).first()
            
            if not latest_quote:
                return html.Div([
                    html.H5(f"{stock.name} ({stock.code})"),
                    html.P(f"交易所: {stock.exchange}"),
                    html.P(f"行业: {stock.industry or '未知'}")
                ])
            
            # 计算涨跌幅
            prev_quote = session.query(DailyQuote).filter(
                DailyQuote.security_id == stock.id,
                DailyQuote.trade_date < latest_quote.trade_date
            ).order_by(desc(DailyQuote.trade_date)).first()
            
            change = 0
            change_pct = 0
            if prev_quote and prev_quote.close:
                change = latest_quote.close - prev_quote.close
                change_pct = change / prev_quote.close * 100
            
            # 显示股票信息和最新行情
            return html.Div([
                html.H5(f"{stock.name} ({stock.code})"),
                html.P(f"交易所: {stock.exchange}"),
                html.P(f"行业: {stock.industry or '未知'}"),
                html.Hr(),
                html.P(f"最新日期: {latest_quote.trade_date.strftime('%Y-%m-%d')}"),
                html.P(f"收盘价: {latest_quote.close:.2f}"),
                html.P([
                    "涨跌幅: ",
                    html.Span(
                        f"{change_pct:+.2f}% ({change:+.2f})",
                        style={'color': 'green' if change >= 0 else 'red'}
                    )
                ]),
                html.P(f"成交量: {int(latest_quote.volume):,}"),
                html.P(f"成交额: {int(latest_quote.amount or 0):,}")
            ])
        finally:
            session.close()
    
    # 回调函数：更新价格走势图
    @dash_app.callback(
        Output('price-chart', 'figure'),
        [Input('stock-dropdown', 'value'),
         Input('date-range', 'start_date'),
         Input('date-range', 'end_date')]
    )
    def update_price_chart(stock_code, start_date, end_date):
        if not stock_code:
            # 返回空图表
            return go.Figure().update_layout(title="请选择证券")
        
        session = Session()
        try:
            # 查询股票信息
            stock = session.query(SecurityInfo).filter(
                SecurityInfo.code == stock_code
            ).first()
            
            if not stock:
                return go.Figure().update_layout(title="未找到证券信息")
            
            # 构建查询条件
            query = session.query(DailyQuote).filter(DailyQuote.security_id == stock.id)
            
            if start_date:
                query = query.filter(DailyQuote.trade_date >= start_date)
            if end_date:
                query = query.filter(DailyQuote.trade_date <= end_date)
            
            # 查询行情数据
            quotes = query.order_by(DailyQuote.trade_date).all()
            
            if not quotes:
                return go.Figure().update_layout(title="所选时间范围内没有数据")
            
            # 转换为DataFrame
            df = pd.DataFrame([{
                'date': q.trade_date,
                'open': q.open,
                'high': q.high,
                'low': q.low,
                'close': q.close,
                'volume': q.volume
            } for q in quotes])
            
            # 创建K线图
            fig = go.Figure(data=[
                go.Candlestick(
                    x=df['date'],
                    open=df['open'],
                    high=df['high'],
                    low=df['low'],
                    close=df['close'],
                    name='K线'
                )
            ])
            
            # 添加成交量图
            fig.add_trace(
                go.Bar(
                    x=df['date'],
                    y=df['volume'],
                    name='成交量',
                    marker_color='rgba(0, 0, 255, 0.3)',
                    yaxis='y2'
                )
            )
            
            # 更新布局
            fig.update_layout(
                title=f"{stock.name} ({stock.code}) 价格走势",
                xaxis_title="日期",
                yaxis_title="价格",
                yaxis2=dict(
                    title="成交量",
                    overlaying="y",
                    side="right",
                    showgrid=False
                ),
                legend=dict(
                    orientation="h",
                    yanchor="bottom",
                    y=1.02,
                    xanchor="right",
                    x=1
                )
            )
            
            # 设置Y轴范围
            min_price = df[['low']].min().min() * 0.95
            max_price = df[['high']].max().max() * 1.05
            fig.update_yaxes(range=[min_price, max_price], constrain='domain')
            
            return fig
        finally:
            session.close()
    
    # 回调函数：更新技术指标图
    @dash_app.callback(
        Output('indicator-chart', 'figure'),
        [Input('stock-dropdown', 'value'),
         Input('date-range', 'start_date'),
         Input('date-range', 'end_date'),
         Input('indicator-dropdown', 'value')]
    )
    def update_indicator_chart(stock_code, start_date, end_date, indicator):
        if not stock_code or not indicator:
            # 返回空图表
            return go.Figure().update_layout(title="请选择证券和技术指标")
        
        session = Session()
        try:
            # 查询股票信息
            stock = session.query(SecurityInfo).filter(
                SecurityInfo.code == stock_code
            ).first()
            
            if not stock:
                return go.Figure().update_layout(title="未找到证券信息")
            
            # 查询行情和技术指标数据
            query = session.query(
                DailyQuote,
                TechnicalIndicator
            ).join(
                TechnicalIndicator,
                DailyQuote.id == TechnicalIndicator.daily_quote_id
            ).filter(
                DailyQuote.security_id == stock.id
            )
            
            if start_date:
                query = query.filter(DailyQuote.trade_date >= start_date)
            if end_date:
                query = query.filter(DailyQuote.trade_date <= end_date)
            
            results = query.order_by(DailyQuote.trade_date).all()
            
            if not results:
                return go.Figure().update_layout(title="所选时间范围内没有技术指标数据")
            
            # 根据选择的指标类型创建不同的图表
            fig = go.Figure()
            
            # 日期和收盘价
            dates = [r[0].trade_date for r in results]
            closes = [r[0].close for r in results]
            
            # 添加收盘价线
            fig.add_trace(go.Scatter(
                x=dates,
                y=closes,
                mode='lines',
                name='收盘价',
                line=dict(color='black')
            ))
            
            if indicator == 'ma':
                # 移动平均线
                ma5 = [r[1].ma5 for r in results]
                ma10 = [r[1].ma10 for r in results]
                ma20 = [r[1].ma20 for r in results]
                ma60 = [r[1].ma60 for r in results]
                
                # 添加各均线
                fig.add_trace(go.Scatter(x=dates, y=ma5, mode='lines', name='MA5', line=dict(color='red')))
                fig.add_trace(go.Scatter(x=dates, y=ma10, mode='lines', name='MA10', line=dict(color='blue')))
                fig.add_trace(go.Scatter(x=dates, y=ma20, mode='lines', name='MA20', line=dict(color='green')))
                fig.add_trace(go.Scatter(x=dates, y=ma60, mode='lines', name='MA60', line=dict(color='purple')))
                
                title = "移动平均线"
                
            elif indicator == 'macd':
                # MACD指标
                macd = [r[1].macd for r in results]
                macd_signal = [r[1].macd_signal for r in results]
                macd_hist = [r[1].macd_hist for r in results]
                
                # 为MACD创建新的Y轴
                fig = make_subplots(rows=2, cols=1, shared_xaxes=True, 
                                    vertical_spacing=0.03, row_heights=[0.7, 0.3])
                
                # 在第一个子图添加收盘价
                fig.add_trace(go.Scatter(
                    x=dates, y=closes, mode='lines', name='收盘价', line=dict(color='black')
                ), row=1, col=1)
                
                # 在第二个子图添加MACD指标
                fig.add_trace(go.Scatter(
                    x=dates, y=macd, mode='lines', name='MACD', line=dict(color='blue')
                ), row=2, col=1)
                
                fig.add_trace(go.Scatter(
                    x=dates, y=macd_signal, mode='lines', name='信号线', line=dict(color='red')
                ), row=2, col=1)
                
                # 添加MACD柱状图
                colors = ['green' if val >= 0 else 'red' for val in macd_hist]
                fig.add_trace(go.Bar(
                    x=dates, y=macd_hist, name='MACD柱状图', marker_color=colors
                ), row=2, col=1)
                
                title = "MACD指标"
                
            elif indicator == 'rsi':
                # RSI指标
                rsi6 = [r[1].rsi6 for r in results]
                rsi12 = [r[1].rsi12 for r in results]
                rsi24 = [r[1].rsi24 for r in results]
                
                # 为RSI创建新的Y轴
                fig = make_subplots(rows=2, cols=1, shared_xaxes=True, 
                                    vertical_spacing=0.03, row_heights=[0.7, 0.3])
                
                # 在第一个子图添加收盘价
                fig.add_trace(go.Scatter(
                    x=dates, y=closes, mode='lines', name='收盘价', line=dict(color='black')
                ), row=1, col=1)
                
                # 在第二个子图添加RSI指标
                fig.add_trace(go.Scatter(
                    x=dates, y=rsi6, mode='lines', name='RSI6', line=dict(color='green')
                ), row=2, col=1)
                
                fig.add_trace(go.Scatter(
                    x=dates, y=rsi12, mode='lines', name='RSI12', line=dict(color='blue')
                ), row=2, col=1)
                
                fig.add_trace(go.Scatter(
                    x=dates, y=rsi24, mode='lines', name='RSI24', line=dict(color='purple')
                ), row=2, col=1)
                
                # 添加超买超卖线
                fig.add_shape(
                    type='line', x0=dates[0], y0=70, x1=dates[-1], y1=70,
                    line=dict(color='red', width=1, dash='dash'),
                    row=2, col=1
                )
                
                fig.add_shape(
                    type='line', x0=dates[0], y0=30, x1=dates[-1], y1=30,
                    line=dict(color='green', width=1, dash='dash'),
                    row=2, col=1
                )
                
                title = "RSI指标"
                
            elif indicator == 'boll':
                # 布林带
                upper = [r[1].boll_upper for r in results]
                middle = [r[1].boll_middle for r in results]
                lower = [r[1].boll_lower for r in results]
                
                # 添加布林带
                fig.add_trace(go.Scatter(
                    x=dates, y=upper, mode='lines', name='上轨', line=dict(color='red')
                ))
                
                fig.add_trace(go.Scatter(
                    x=dates, y=middle, mode='lines', name='中轨', line=dict(color='orange')
                ))
                
                fig.add_trace(go.Scatter(
                    x=dates, y=lower, mode='lines', name='下轨', line=dict(color='green')
                ))
                
                # 填充布林带区域
                fig.add_trace(go.Scatter(
                    x=dates + dates[::-1],
                    y=upper + lower[::-1],
                    fill='toself',
                    fillcolor='rgba(0,100,80,0.2)',
                    line=dict(color='rgba(255,255,255,0)'),
                    hoverinfo='skip',
                    showlegend=False
                ))
                
                title = "布林带指标"
            
            # 更新布局
            fig.update_layout(
                title=f"{stock.name} ({stock.code}) {title}",
                xaxis_title="日期",
                yaxis_title="价格",
                legend=dict(
                    orientation="h",
                    yanchor="bottom",
                    y=1.02,
                    xanchor="right",
                    x=1
                )
            )
            
            # 如果是子图，设置第二个Y轴
            if indicator in ['macd', 'rsi']:
                fig.update_yaxes(title_text="价格", row=1, col=1)
                
                if indicator == 'macd':
                    fig.update_yaxes(title_text="MACD值", row=2, col=1)
                elif indicator == 'rsi':
                    fig.update_yaxes(title_text="RSI值", range=[0, 100], row=2, col=1)
            
            return fig
        finally:
            session.close()
    
    return dash_app


def create_macro_dashboard(server):
    """
    创建宏观经济数据仪表盘
    
    Args:
        server: Flask服务器实例
    
    Returns:
        Dash应用实例
    """
    dash_app = dash.Dash(
        name='macro_dashboard',
        server=server,
        url_base_pathname='/dash/macro/',
        external_stylesheets=[dbc.themes.BOOTSTRAP]
    )
    
    # 获取所有可用指标
    session = Session()
    indicators = session.query(
        MacroEconomicData.indicator,
        func.count(MacroEconomicData.id).label('count')
    ).group_by(MacroEconomicData.indicator).order_by(
        desc('count')
    ).all()
    
    indicator_options = [{'label': ind[0], 'value': ind[0]} for ind in indicators]
    
    # 获取所有可用地区
    regions = session.query(
        MacroEconomicData.region,
        func.count(MacroEconomicData.id).label('count')
    ).group_by(MacroEconomicData.region).order_by(
        desc('count')
    ).all()
    
    region_options = [{'label': reg[0], 'value': reg[0]} for reg in regions]
    session.close()
    
    # 定义布局
    dash_app.layout = html.Div([
        dbc.Container([
            html.H1("宏观经济数据分析", className="text-center my-4"),
            
            dbc.Row([
                dbc.Col([
                    dbc.Card([
                        dbc.CardHeader("指标选择"),
                        dbc.CardBody([
                            dcc.Dropdown(
                                id='indicator-dropdown',
                                options=indicator_options,
                                value=indicator_options[0]['value'] if indicator_options else None,
                                placeholder="选择宏观经济指标..."
                            )
                        ])
                    ])
                ], width=6),
                
                dbc.Col([
                    dbc.Card([
                        dbc.CardHeader("地区选择"),
                        dbc.CardBody([
                            dcc.Dropdown(
                                id='region-dropdown',
                                options=region_options,
                                value=[region_options[0]['value']] if region_options else None,
                                placeholder="选择地区...",
                                multi=True
                            )
                        ])
                    ])
                ], width=6)
            ], className="mb-4"),
            
            dbc.Row([
                dbc.Col([
                    dbc.Card([
                        dbc.CardHeader("时间范围"),
                        dbc.CardBody([
                            dcc.RangeSlider(
                                id='year-slider',
                                min=1990,
                                max=datetime.now().year,
                                value=[2010, datetime.now().year],
                                marks={i: str(i) for i in range(1990, datetime.now().year + 1, 5)},
                                step=1
                            )
                        ])
                    ])
                ], width=12)
            ], className="mb-4"),
            
            dbc.Row([
                dbc.Col([
                    dbc.Card([
                        dbc.CardHeader("宏观经济数据趋势"),
                        dbc.CardBody([
                            dcc.Graph(id='macro-trend-chart')
                        ])
                    ])
                ], width=12)
            ], className="mb-4"),
            
            dbc.Row([
                dbc.Col([
                    dbc.Card([
                        dbc.CardHeader("地区对比"),
                        dbc.CardBody([
                            dcc.Graph(id='region-comparison-chart')
                        ])
                    ])
                ], width=12)
            ])
        ], fluid=True)
    ])
    
    # 回调函数：更新宏观经济数据趋势图
    @dash_app.callback(
        Output('macro-trend-chart', 'figure'),
        [Input('indicator-dropdown', 'value'),
         Input('region-dropdown', 'value'),
         Input('year-slider', 'value')]
    )
    def update_macro_trend_chart(indicator, regions, years):
        if not indicator or not regions:
            return go.Figure().update_layout(title="请选择指标和地区")
        
        # 确保regions是列表
        if not isinstance(regions, list):
            regions = [regions]
        
        session = Session()
        try:
            # 查询宏观经济数据
            query = session.query(MacroEconomicData).filter(
                MacroEconomicData.indicator == indicator,
                MacroEconomicData.region.in_(regions),
                MacroEconomicData.time_point >= datetime(years[0], 1, 1).date(),
                MacroEconomicData.time_point <= datetime(years[1], 12, 31).date()
            ).order_by(
                MacroEconomicData.region,
                MacroEconomicData.time_point
            ).all()
            
            if not query:
                return go.Figure().update_layout(title="所选条件下没有数据")
            
            # 获取单位
            unit = query[0].unit if query[0].unit else ""
            
            # 创建趋势图
            fig = go.Figure()
            
            # 按地区分组
            for region in regions:
                region_data = [d for d in query if d.region == region]
                if region_data:
                    fig.add_trace(go.Scatter(
                        x=[d.time_point for d in region_data],
                        y=[d.value for d in region_data],
                        mode='lines+markers',
                        name=region
                    ))
            
            # 更新布局
            fig.update_layout(
                title=f"{indicator}趋势 ({years[0]}年-{years[1]}年)",
                xaxis_title="日期",
                yaxis_title=f"值 ({unit})",
                legend_title="地区",
                hovermode="x unified"
            )
            
            return fig
        finally:
            session.close()
    
    # 回调函数：更新地区对比图
    @dash_app.callback(
        Output('region-comparison-chart', 'figure'),
        [Input('indicator-dropdown', 'value'),
         Input('region-dropdown', 'value'),
         Input('year-slider', 'value')]
    )
    def update_region_comparison_chart(indicator, regions, years):
        if not indicator or not regions:
            return go.Figure().update_layout(title="请选择指标和地区")
        
        # 确保regions是列表
        if not isinstance(regions, list):
            regions = [regions]
        
        session = Session()
        try:
            # 查询最新年份的数据
            latest_data = []
            for region in regions:
                # 获取每个地区最新的数据
                latest = session.query(MacroEconomicData).filter(
                    MacroEconomicData.indicator == indicator,
                    MacroEconomicData.region == region,
                    MacroEconomicData.time_point >= datetime(years[0], 1, 1).date(),
                    MacroEconomicData.time_point <= datetime(years[1], 12, 31).date()
                ).order_by(
                    desc(MacroEconomicData.time_point)
                ).first()
                
                if latest:
                    latest_data.append(latest)
            
            if not latest_data:
                return go.Figure().update_layout(title="所选条件下没有数据")
            
            # 获取单位
            unit = latest_data[0].unit if latest_data[0].unit else ""
            
            # 创建条形图
            fig = go.Figure()
            
            # 添加条形图
            fig.add_trace(go.Bar(
                x=[d.region for d in latest_data],
                y=[d.value for d in latest_data],
                text=[f"{d.value:.2f}" for d in latest_data],
                textposition='auto',
                hoverinfo='text',
                hovertext=[f"{d.region}: {d.value:.2f} {unit}<br>日期: {d.time_point}" for d in latest_data]
            ))
            
            # 更新布局
            fig.update_layout(
                title=f"{indicator}地区对比 (最新数据)",
                xaxis_title="地区",
                yaxis_title=f"值 ({unit})",
                uniformtext_minsize=8,
                uniformtext_mode='hide'
            )
            
            return fig
        finally:
            session.close()
    
    return dash_app


# 注册所有Dash仪表盘
def register_dashboards(server):
    """注册所有仪表盘到Flask服务器"""
    # 任务监控仪表盘
    create_task_dashboard(server)
    
    # 市场数据仪表盘
    create_market_dashboard(server)
    
    # 宏观经济数据仪表盘
    create_macro_dashboard(server)
    
    # 可以在此处添加更多仪表盘...
    
    return True